package xj.graph2d;

import java.awt.geom.Rectangle2D;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;

import xj.app.Application;

public abstract class Document extends Observable {

  public static final int DEFAULT_CANVAS_WIDTH = 1000;

  public static final int DEFAULT_CANVAS_HEIGHT = 800;

  public static final int DEFAULT_MARGIN = 20;

  public static final int UNIT_PIXEL = 100;

  public static final int UNIT_INCH = 101;

  public static final int UNIT_CM = 102;

  public static final int POINTS_PER_INCH = 72;

  public static final int POINTS_PER_CM = 28;

  public enum DocumentType {
      Generic_Diagram, 
      Flow_Graph_Diagram, 
      Visual_Class_Diagram, 
      UML_Diagram, 
      UML_Class_Diagram, 
      UML_Activity_Diagram, 
      UML_Communication_Diagram, 
      UML_Component_Diagram, 
      UML_Composite_Diagram, 
      UML_Deployment_Diagram, 
      UML_Interaction_Diagram, 
      UML_Object_Diagram, 
      UML_Package_Diagram, 
      UML_Sequence_Diagram, 
      UML_State_Diagram, 
      UML_Timimg_Diagram, 
      UML_Use_Case_Diagram
  };

  public static final String[] DocumentTypeNames = { 
    "UMLClass",
    "UMLPackage", 
    "UMLUseCase", 
    "UMLState",
    "UMLSequence", 
    "UMLActivity",
    "FlowGraph",
    "VisualClass",
    "Default",
  };

  public static final String[] FolderTypeNames = { 
    "UMLModel", 
    "UMLPackage",
    // "Documentation",
    // "SourceCode",
    // "Test",
    "DocumentFolder"
  };

  static public DocumentType toDocumentType(String name) {
    if (name != null) {
      name = name.replaceAll("_", " ");
      name = name.toLowerCase();
      if (name.equals("default") ||
	  name.equals("generic")) { 
	return DocumentType.Generic_Diagram;
      }
      if (name.indexOf("flow graph") >= 0 || 
	  name.indexOf("flowgraph") >= 0) { 
	return DocumentType.Flow_Graph_Diagram;
      }
      if (name.indexOf("visual class") >= 0 || 
	  name.indexOf("visualclass") >= 0) { 
	return DocumentType.Visual_Class_Diagram;
      }
      if (name.startsWith("uml")) { 
	if (name.indexOf("class") > 0) {
	  return DocumentType.UML_Class_Diagram;
	} else if (name.indexOf("activity") > 0) {
	  return DocumentType.UML_Activity_Diagram;
	} else if (name.indexOf("communication") > 0) {
	  return DocumentType.UML_Communication_Diagram;
	} else if (name.indexOf("component") > 0) {
	  return DocumentType.UML_Component_Diagram;
	} else if (name.indexOf("composite") > 0) {
	  return DocumentType.UML_Composite_Diagram;
	} else if (name.indexOf("deployment") > 0) {
	  return DocumentType.UML_Deployment_Diagram;
	} else if (name.indexOf("interaction") > 0) {
	  return DocumentType.UML_Interaction_Diagram;
	} else if (name.indexOf("object") > 0) {
	  return DocumentType.UML_Object_Diagram;
	} else if (name.indexOf("package") > 0) {
	  return DocumentType.UML_Package_Diagram;
	} else if (name.indexOf("sequence") > 0) {
	  return DocumentType.UML_Sequence_Diagram;
	} else if (name.indexOf("state") > 0) {
	  return DocumentType.UML_State_Diagram;
	} else if (name.indexOf("timimg") > 0) {
	  return DocumentType.UML_Timimg_Diagram;
	} else if (name.indexOf("use case") > 0 ||
		   name.indexOf("usecase") > 0) {
	  return DocumentType.UML_Use_Case_Diagram;
	}
	return DocumentType.UML_Diagram;
      }
    }
    return DocumentType.Generic_Diagram;
  }

  static public String getDefaultFilename(DocumentType type) { 
    String newname = null; 
    if (type != null) {       
      switch (type) {
      case Generic_Diagram:
	newname = "Diagram";
	break;
      case Flow_Graph_Diagram:
	newname = "FlowGraph";
	break;
      case Visual_Class_Diagram:
	newname = "VisualClass";
	break;
      case UML_Diagram:
	newname = "UMLDiagram";
	break;
      case UML_Class_Diagram:
	newname = "ClassDiagram";
	break;
      case UML_Activity_Diagram:
	newname = "ActivityDiagram";
	break;
      case UML_Communication_Diagram:
	newname = "CommunicationDiagram";
	break;
      case UML_Component_Diagram:
	newname = "ComponentDiagram";
	break;
      case UML_Composite_Diagram:
	newname = "CompositeDiagram";
	break;
      case UML_Deployment_Diagram:
	newname = "DeploymentDiagram";
	break;
      case UML_Interaction_Diagram:
	newname = "InteractionDiagram";
	break;
      case UML_Object_Diagram:
	newname = "ObjectDiagram";
	break;
      case UML_Package_Diagram:
	newname = "PackageDiagram";
	break;
      case UML_Sequence_Diagram:
	newname = "SequenceDiagram";
	break;
      case UML_State_Diagram:
	newname = "StateDiagram";
	break;
      case UML_Timimg_Diagram:
	newname = "TimingDiagram";
	break;
      case UML_Use_Case_Diagram:
	newname = "UseCaseDiagram";
	break;
      default:
	newname = "Diagram";
      }
    }
    return newname;
  }

  static public String getDocumentTypeString(DocumentType type) { 
    if (type != null) { 
      switch (type) { 
      case Generic_Diagram:
	return "Generic Diagram";
      case Flow_Graph_Diagram:
	return "Flow Graph";
      case Visual_Class_Diagram:
	return "Visual Class";
      case UML_Diagram:
	return "UML Diagram";
      case UML_Class_Diagram:
	return "UML Class Diagram";
      case UML_Activity_Diagram:
	return "UML Activity Diagram";
      case UML_Communication_Diagram:
	return "UML Communication Diagram";
      case UML_Component_Diagram:
	return "UML Component Diagram";
      case UML_Composite_Diagram:
	return "UML Composite Diagram";
      case UML_Deployment_Diagram:
	return "UML Deployment Diagram";
      case UML_Interaction_Diagram:
	return "UML Interaction Diagram";
      case UML_Object_Diagram:
	return "UML Object Diagram";
      case UML_Package_Diagram:
	return "UML Package Diagram";
      case UML_Sequence_Diagram:
	return "UML Sequence Diagram";
      case UML_State_Diagram:
	return "UML State Diagram";
      case UML_Timimg_Diagram:
	return "UML Timing Diagram";
      case UML_Use_Case_Diagram:
	return "UML Use Case Diagram";
      }
    }
    return "Unknown";
  }

  public String getExtension(int filetype) {
    return "vml";
  }

  static public String getDefaultExtension(DocumentType type) {
    String ext = null;
    if (type != null) {
      ext = defaultExtension.get(type);
    }
    if (ext == null) {
      ext = "vml";
    }
    return ext;
  }

  static public String setFileExtension(String filename, String ext) {
    if (filename != null && ext != null) {
      String fext = null;
      int i = filename.lastIndexOf('.');
      int j = filename.lastIndexOf(File.separator);
      if (i > j && i < filename.length() - 1) {
	fext = filename.substring(i + 1).toLowerCase();
      }
      if (fext != null) {
	if (!ext.equals(fext)) {
	  filename = filename.substring(0, i) + "." + ext;
	}
      } else {
	filename += ("." + ext);
      }
    }
    return filename;
  }

  abstract public Rectangle2D getBounds();

  public DocumentType getDocumentType() {
    return doctype;
  }

  public void setDocumentType(DocumentType doctype) {
    this.doctype = doctype;
    initModel();    
  }

  public void initModel() {
  }

  public float getMarginWidth() {
    return marginWidth;
  }

  public void setMarginWidth(float marginWidth) {
    this.marginWidth = marginWidth;
  }

  public float getMarginHeight() {
    return marginHeight;
  }

  public void setMarginHeight(float marginHeight) {
    this.marginHeight = marginHeight;
  }

  public float getCanvasWidth() {
    return canvasWidth;
  }

  public void setCanvasWidth(float canvasWidth) {
    this.canvasWidth = canvasWidth;
  }

  public float getCanvasHeight() {
    return canvasHeight;
  }

  public void setCanvasHeight(float canvasHeight) {
    this.canvasHeight = canvasHeight;
  }

  public int getUnit() {
    return unit;
  }

  public void setUnit(int unit) {
    this.unit = unit;
  }

  public static String getUnitString(int u) {
    switch (u) {
    case Document.UNIT_INCH:
      return "inch";
    case Document.UNIT_CM:
      return "cm";
    case Document.UNIT_PIXEL:
    default:
      return "pixel";
    }
  }

  public Application getApplication() {
    return application;
  }

  public void setApplication(Application application) {
    this.application = application;
  }

  public String getAppName() {
    if (application != null) {
      return application.getAppName();
    }
    return null;
  }

  public String getVersion() {
    if (application != null) {
      return application.getVersion();
    }
    return null;
  }

  public String getReleaseDate() {
    if (application != null) {
      return application.getReleaseDate();
    }
    return null;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setDocumentChangeListener(DocumentChangeListener listener) {
    this.listener = listener;
  }

  public ViewOptions getViewOptions() { 
    return options; 
  }

  public void setViewOptions(ViewOptions op) { 
    options = op; 
  }

  public abstract boolean saveFile() 
    throws java.io.IOException, DocumentException;

  protected Document() {
    this(null);
  }

  protected Document(Application application) {
    this.application = application;
  }

  protected DocumentType doctype;

  protected float marginWidth = DEFAULT_MARGIN;

  protected float marginHeight = DEFAULT_MARGIN;

  protected float canvasWidth = DEFAULT_CANVAS_WIDTH;

  protected float canvasHeight = DEFAULT_CANVAS_HEIGHT;

  protected int unit = UNIT_PIXEL;

  protected String name;

  protected DocumentChangeListener listener;

  protected ViewOptions options; 

  protected Application application;

  protected static final Map<DocumentType, String> defaultExtension;

  static {
    defaultExtension = new HashMap<DocumentType, String>();
    defaultExtension.put(DocumentType.Generic_Diagram, "vml");
    defaultExtension.put(DocumentType.UML_Class_Diagram, "vml");
    defaultExtension.put(DocumentType.UML_Diagram, "vml");
  }

}
